//<GUI menuname="Split SDFile..." tooltip="Split an SDFile into several files"/>

/******************************************************************************************************
Copyright (C) 2009 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/
/*globals FileDialog, settings, Dir, File, Dialog, print, ComboBox, SpinBox, LineEdit, ToolButton, GroupBox, CheckBox, TextStream, MessageBox, mainWindow,
Serialization, Str*/
/*jslint plusplus: true, indent: 4, continue: true, bitwise: true*/

function splitSDFile() {
	"use strict";

	var inDirSettingsKey = "Split SDFile/Input Directory",
		outDirSettingsKey = "Split SDFile/Output Directory",
		outFormatSettingsKey = "Split SDFile/Output Format",
		chunkSizeSettingsKey = "Split SDFile/Chunk Size",
		useHeaderSettingsKey = "Split SDFile/Use Header",
		useTagSettingsKey = "Split SDFile/Use Tag",
		tagSettingsKey = "Split SDFile/Tag",
		inFileName,
		dialog,
		dirName,
		cbFormat,
		sbChunkSize,
		leDirectory,
		tbOpenDir,
		gbFolder,
		chUseHeader,
		chUseTag,
		leTag,
		outDirName,
		outFormat,
		chunkSize,
		useHeader,
		useTag,
		tag,
		startTime,
		inFile,
		s,
		inStream,
		dw,
		ok,
		outFileCount,
		chunkCount,
		buffer,
		endConnectionTableWritten,
		tagFileName,
		readingTag,
		serialization,
		line,
		outFileName;

	inFileName = FileDialog.getOpenFileName("SDfile (*.sdf);;All files (*.*)", "Select File", settings.value(inDirSettingsKey, Dir.home()));
	if (!inFileName.length) {
		return;
	}
	settings.setValue(inDirSettingsKey, File.absDirPath(inFileName));

	dialog = new Dialog("Output Options");
	dialog.onOpenDir = function () {
		dirName = FileDialog.getExistingDirectory(this.text);
		print("Directory: " + dirName);
		if (dirName.length > 0) {
			this.text = dirName;
		}
	};

	dialog.onCBFormatChanged = function () {
		if (this.currentText === "mol") {
			this.oldValue = sbChunkSize.value;
			sbChunkSize.maximum = 1;
			sbChunkSize.value = 1;
		} else {
			sbChunkSize.maximum = 65535;
			if (typeof (this.oldValue) === "number") {
				sbChunkSize.value = this.oldValue;
			}
		}
	};

	cbFormat = new ComboBox();
	cbFormat.addItem("mnova");
	cbFormat.addItem("mol");
	cbFormat.addItem("sdf");
	cbFormat['activated(QString)'].connect(cbFormat, dialog.onCBFormatChanged);
	cbFormat.currentIndex = settings.value(outFormatSettingsKey, 0);

	sbChunkSize = new SpinBox();
	sbChunkSize.minimum = 1;
	sbChunkSize.maximum = 65535;
	sbChunkSize.value = settings.value(chunkSizeSettingsKey, 1);

	leDirectory = new LineEdit();
	leDirectory.label = "Directory:";
	leDirectory.text = settings.value(outDirSettingsKey, Dir.home());

	tbOpenDir = new ToolButton();
	tbOpenDir.text = "...";
	tbOpenDir.clicked.connect(leDirectory, dialog.onOpenDir);

	gbFolder = new GroupBox();
	gbFolder.title = "Output";
	gbFolder.add("Format:", cbFormat);
	gbFolder.add("Chunk size:", sbChunkSize);
	gbFolder.add(leDirectory, tbOpenDir);
	dialog.add(gbFolder);

	chUseHeader = new CheckBox();
	chUseHeader.text = "Use header for file name";
	chUseHeader.checked = settings.value(useHeaderSettingsKey, false);

	dialog.add(chUseHeader);

	chUseTag = new CheckBox();
	chUseTag.text = "Use tag for file name";
	chUseTag.checked = settings.value(useTagSettingsKey, false);

	leTag = new LineEdit();
	leTag.text = settings.value(tagSettingsKey, "1234");

	if (chUseTag.checked) {
		leTag.enabled = true;
	} else {
		leTag.enabled = false;
	}

	chUseHeader.stateChanged.connect(function (checked) {
		if (checked === 2) {
			chUseTag.checked = false;
			leTag.enabled = false;
		}
	});

	chUseTag.stateChanged.connect(function (checked) {
		if (checked === 2) {
			chUseHeader.checked = false;
			leTag.enabled = true;
		} else {
			leTag.enabled = false;
		}
	});

	dialog.add(chUseTag, leTag);

	if (!dialog.exec()) {
		return undefined;
	}

	outDirName = leDirectory.text;
	outFormat = cbFormat.currentText;
	chunkSize = sbChunkSize.value;
	useHeader = chUseHeader.checked;
	useTag = chUseTag.checked;
	tag = leTag.text;

	if (!outDirName.length) {
		return;
	}

	settings.setValue(outDirSettingsKey, outDirName);
	settings.setValue(outFormatSettingsKey, cbFormat.currentIndex);
	settings.setValue(chunkSizeSettingsKey, chunkSize);
	settings.setValue(useHeaderSettingsKey, useHeader);
	settings.setValue(useTagSettingsKey, useTag);
	settings.setValue(tagSettingsKey, tag);

	// Converts number to string, padding with leading 0's
	function pad(aNumber) {
		var result = "" + aNumber;
		while (result.length < 6) {
			result = "0" + result;
		}
		return result;
	}

	// Saves given array of lines to temporary sdf file and read temporary file into mnova.
	function processBuffer(aLines, aFileName) {
		var outStream, l, ok = true,
			tempFile = new File(aFileName);

		tempFile.open(File.WriteOnly);
		outStream = new TextStream(tempFile);
		for (l = 0; l < aLines.length; l++) {
			outStream.writeln(aLines[l]);
		}
		tempFile.close();
		// Open temporary file and read contents
		if (s.open(aFileName, "SDfile (*.sdf)")) {
			tempFile.remove();
		} else {
			MessageBox.critical("Could not open file '" + aFileName + "'.");
			ok = mainWindow.waitForInput("Continue with conversion?");
			mainWindow.setBusy("Working...");
		}
		return ok;
	}

	// Process file
	startTime = new Date();
	print("It is now " + startTime.toString());

	inFile = new File(inFileName);
	if (!inFile.open(File.ReadOnly)) {
		MessageBox.critical("Could not open file '" + inFileName + "'.");
		return;
	}
	inStream = new TextStream(inFile);

	s = new Serialization(serialization);
	s.fileHistory = false;

	dw = mainWindow.newWindow();
	ok = true;
	outFileCount = 0;
	chunkCount = 0;
	buffer = [];
	endConnectionTableWritten = false;
	tagFileName = "";
	readingTag = false;

	while (!inStream.atEnd() && ok) {
		line = inStream.readLine();
		//print("'" + line + "'");

		if (readingTag) {
			if (line.indexOf("> <") === -1) {
				tagFileName += line;
			} else {
				readingTag = false;
			}
		}

		if (useTag) {
			if (line === "> <" + tag + ">") {
				readingTag = true;
			}
		}

		if (line === "$$$$") {
			mainWindow.setStatusMessage("Processing structure " + outFileCount + " ...");
			// EGW1539: Add "M END" to connection table
			if (!endConnectionTableWritten) {
				buffer.push("M  END");
			}
			buffer.push("$$$$");
			endConnectionTableWritten = false;
			// Write temporary file and  re-read into Mnova
			ok = processBuffer(buffer, Dir.temp() + "/" + Str.fileNameFromPath(inFileName) + "-" + pad(outFileCount) + ".sdf");
			outFileCount++;
			// Write output file every chunkSize items
			if (((outFileCount % chunkSize) === 0) && ok) {
				outFileName = outDirName + "/";

				if (useHeader) {
					outFileName += Str.trimStr(buffer[0]);
				} else if (useTag) {
					if (tagFileName !== "") {
						outFileName += tagFileName;
					} else {
						outFileName += "tagNotFound_" + Str.fileNameFromPath(inFileName) + "-" + (chunkSize > 1 ? pad(chunkCount * chunkSize + 1) + "-" : "") + pad(outFileCount);
					}
				} else {
					outFileName += Str.fileNameFromPath(inFileName) + "-" + (chunkSize > 1 ? pad(chunkCount * chunkSize + 1) + "-" : "") + pad(outFileCount);
				}
				outFileName += "." + outFormat;
				mainWindow.setStatusMessage("Writing " + outFileName + "...");
				//print("Writing file " + outFileName);
				dw.setSelectedPages(dw.pages()); // Select all pages in document, needed for saving all molecules into sdf
				s.save(outFileName, outFormat);
				tagFileName = "";
				dw.close();
				dw = mainWindow.newWindow();
				chunkCount++;
			}
			// Looks better in mnova if each molecule goes onto a new page
			if (chunkSize > 1) {
				dw.newPage();
			}
			// Prepare buffer for next molecule
			buffer = [];
		} else if (line === "M END" || line === "M  END") {
			buffer.push("M  END");
			endConnectionTableWritten = true;
		} else {
			if (line.substr(0, 1) === ">" && !endConnectionTableWritten) {
				// EGW1539: Add "M END" to connection table
				buffer.push("M  END");
				endConnectionTableWritten = true;
			}
			buffer.push(line);
		}
	}
	// Write remaining items
	if ((buffer.length > 0) && ok) {
		outFileName = outDirName + "/";
		if (useHeader) {
			outFileName += Str.trimStr(buffer[0]);
		} else if (useTag) {
			if (tagFileName !== "") {
				outFileName += tagFileName;
			} else {
				outFileName += "tagNotFound_" + Str.fileNameFromPath(inFileName) + "-" + (chunkSize > 1 ? pad(chunkCount * chunkSize + 1) + "-" : "") + pad(outFileCount);
			}
		} else {
			outFileName += Str.fileNameFromPath(inFileName) + "-" + (chunkSize > 1 ? pad(chunkCount * chunkSize + 1) + "-" : "") + pad(outFileCount);
		}
		outFileName += "." + outFormat;
		//mainWindow.setStatusMessage("Writing " + outFileName + "...");
		//print("Writing file " + outFileName);
		dw.setSelectedPages(dw.pages()); // Select all pages in document, needed for saving all molecules into sdf
		s.save(outFileName, outFormat);
		dw.close();
	}
	// All done
	inFile.close();
	mainWindow.endBusy();
	print("All done in " + ((new Date() - startTime) / 1000) + " seconds.");
}

